﻿
namespace Magnet.Models.NHFluent.AutoMapping
{

    #region Using NameSaces
    using NHibernate;
    using NHibernate.Cfg;
    using FluentNHibernate.Cfg;
    using FluentNHibernate.Cfg.Db;
    using FluentNHibernate.Automapping;
    using FluentNHibernate.Conventions.Helpers;
    using Magnet.Models.NHFluent.AutoMapping.Entities;
    using Magnet.Models.NHFluent.AutoMapping.Conventions;
    #endregion

    public static class Schemas
    {
        public static readonly string NHFluentAuto = "NHFAuto";
    }

    internal class NHContext
    {
        public static ISessionFactory CreateSessionFactory()
        {
            
            return Fluently.Configure()
                .Database(
                    MsSqlConfiguration.MsSql2005
                      .ConnectionString(c => c
                        .Server("princepc")
                        .Database("NHibernate")
                        .Username("beta")
                        .Password("beta"))
                )
                .Mappings(m => m.AutoMappings.Add(
                        AutoMap.AssemblyOf<Product>()
                        .Where(t => t.Namespace == "Magnet.Models.NHFluent.AutoMapping.Entities")
                        .Setup(s =>
                            {
                                s.IsComponentType = t => t == typeof(Address);
                                s.GetComponentColumnPrefix = p => string.Empty; 
                            })
                        .Conventions.Add<PrimaryKeyConvention>()
                        .Conventions.Add<CustomForeignKeyConvention>()
                        .Conventions.Add<DefaultStringLengthConvention>()
                        .Conventions.Add<CustomManyToManyTableNameConvention>()
                        .Conventions.Add(
                            ConventionBuilder.Class.Always(c => c.Schema(Schemas.NHFluentAuto)),
                            ConventionBuilder.HasMany.Always(c => c.Schema(Schemas.NHFluentAuto)),
                            ConventionBuilder.HasManyToMany.Always(c => c.Schema(Schemas.NHFluentAuto)),
                            DefaultCascade.All()
                        )
                    )
                )
                .BuildSessionFactory();

        }

        public static void BuildSchema(Configuration config)
        {
            //// delete the existing db on each run
            //if (File.Exists(DbFile))
            //    File.Delete(DbFile);

            //// this NHibernate tool takes a configuration (with mapping info in)
            //// and exports a database schema from it
            //new SchemaExport(config)
            //    .Create(false, true);
        }

    }
}

namespace Magnet.Models.NHFluent.AutoMapping.Conventions
{
    #region Using NameSpaces
    using System;
    using System.Reflection;
    using FluentNHibernate;
    using FluentNHibernate.Conventions;
    using FluentNHibernate.Conventions.Instances;
    using FluentNHibernate.Conventions.Inspections;
    #endregion

    public class PrimaryKeyConvention : IIdConvention
    {
        public void Apply(IIdentityInstance instance)
        {
            instance.Column("Id");
        }
    }

    public class CustomForeignKeyConvention : ForeignKeyConvention
    {
        //protected override string GetKeyName(PropertyInfo property, Type type)
        //{
        //    if (property == null)
        //        return type.Name + "Id";

        //    return property.Name + "Id";
        //}

        protected override string GetKeyName(Member property, Type type)
        {
            if (property == null)
                return type.Name + "Id";

            return property.Name + "Id";
        }
    }

    public class DefaultStringLengthConvention : IPropertyConvention
    {
        public void Apply(IPropertyInstance instance)
        {
            instance.Length(100);
        }
    }

    public class CustomManyToManyTableNameConvention : ManyToManyTableNameConvention 
    {
        protected override string GetBiDirectionalTableName(IManyToManyCollectionInspector collection, IManyToManyCollectionInspector otherSide)
        {
            return otherSide.EntityType.Name + collection.EntityType.Name;
        }

        protected override string GetUniDirectionalTableName(IManyToManyCollectionInspector collection)
        {
            return collection.EntityType.Name;
        }
    }

}


